home *** CD-ROM | disk | FTP | other *** search
- /* net/rom level 3 low level processing
- * Copyright 1989 by Daniel M. Frank, W9NK. Permission granted for
- * non-commercial distribution only.
- */
- /* Mods by PA0GRI and WG7J */
-
- #include "global.h"
- #ifdef NETROM
- #include "ctype.h"
- #include "commands.h"
- #include "mbuf.h"
- #include "pktdrvr.h"
- #include "arp.h"
- #include "netrom.h"
- #include "trace.h"
-
- #if !defined(_lint)
- static char rcsid[] OPTIONAL = "$Id: nr3.c,v 1.21 1997/09/07 21:18:28 root Exp root $";
- #endif
-
- /* IF the following is defined,
- * when we receive a nodes broadcast of a new neighbour,
- * we will immediately respond with a nodes broadcast on that interface
- * This speeds up route discovery at bootup etc..
- * 920422 - WG7J
- */
- #define NR_BC_RESPOND 1
-
- static int accept_bc (char *addr, struct iface * ifp);
- struct nr_bind *find_best (struct nr_bind * list, unsigned obso);
- static struct nr_bind *find_binding (struct nr_bind * list, struct nrnbr_tab * neighbor);
- struct nrnbr_tab *find_nrnbr (char *, struct iface *);
- void nrresetlinks (struct nrroute_tab * rp); /* s/b in a header file */
- static struct nrnf_tab *find_nrnf (char *, struct iface *);
- static struct nr_bind *find_worst (struct nr_bind * list);
- extern void doobsotick (void);
-
- static struct raw_nr *Raw_nr;
- static int nr_aliasck (char *alias);
-
- struct nrnbr_tab *Nrnbr_tab[NRNUMCHAINS];
- struct nrroute_tab *Nrroute_tab[NRNUMCHAINS];
- struct nrnf_tab *Nrnf_tab[NRNUMCHAINS];
- unsigned Nr_nfmode = NRNF_NOFILTER;
- unsigned short Nr_ttl = 10;
- static unsigned Obso_init = 6; /* The obsolescence count initializer */
- static unsigned Obso_minbc = 5; /* The threshhold at which routes becoming obsolete are not broadcast */
-
- /* The maximum number of routes maintained for a destination. */
- /* If the list fills up, only the highest quality routes are */
- /* kept. This limiting is done to avoid possible over-use of */
- /* memory for routing tables in closely spaced net/rom networks. */
- static unsigned Nr_maxroutes = 5;
-
- unsigned Nr_autofloor = 10;
- int Nr_derate = 1; /* Allow automatic derating of routes */
- int Nr_promisc = 0; /* behave promisuously with nr bcasts or not? */
- struct iface *Nr_iface;
- static const char temproute[] = "##temp";
-
- extern char Nralias[ALEN + 1];
-
-
- /* send a NET/ROM layer 3 datagram */
- void
- nr3output (dest, data)
- char *dest;
- struct mbuf *data;
- {
- struct nr3hdr n3hdr;
- struct mbuf *n3b;
-
- memcpy (n3hdr.dest, dest, AXALEN); /* copy destination field */
- n3hdr.ttl = Nr_ttl; /* time to live from initializer parm */
-
- if ((n3b = htonnr3 (&n3hdr)) == NULLBUF) {
- free_p (data);
- return;
- }
- append (&n3b, data);
- /* The null interface indicates that the packet needs to have */
- /* an appropriate source address inserted by nr_route */
- nr_route (n3b, NULLAX25);
- }
-
-
- /* send IP datagrams across a net/rom network connection */
- int
- nr_send (bp, iface, gateway, prec, del, tput, rel)
- struct mbuf *bp;
- struct iface *iface;
- uint32 gateway;
- int prec OPTIONAL;
- int del OPTIONAL;
- int tput OPTIONAL;
- int rel OPTIONAL;
- {
- struct arp_tab *arp;
-
- dump (iface, IF_TRACE_OUT, CL_NETROM, bp);
-
- if ((arp = arp_lookup (ARP_NETROM, gateway, iface)) == NULLARP) {
- free_p (bp); /* drop the packet if no route */
- return -1;
- }
- iface->rawsndcnt++;
- Nr_iface->ipsndcnt++;
- iface->lastsent = Nr_iface->lastsent = secclock ();
-
- nr_sendraw (arp->hw_addr, NRPROTO_IP, NRPROTO_IP, bp);
- return 0;
- }
-
-
- /* Send arbitrary protocol data on top of a NET/ROM connection */
- void
- nr_sendraw (dest, family, proto, data)
- char *dest;
- unsigned family;
- unsigned proto;
- struct mbuf *data;
- {
- struct mbuf *pbp;
- struct nr4hdr n4hdr;
-
- /* Create a "network extension" transport header */
- n4hdr.opcode = NR4OPPID;
- n4hdr.u.pid.family = uchar(family);
- n4hdr.u.pid.proto = uchar(proto);
-
- if ((pbp = htonnr4 (&n4hdr)) == NULLBUF) {
- free_p (data);
- return;
- }
- append (&pbp, data); /* Append the data to that */
- nr3output (dest, pbp); /* and pass off to level 3 code */
- }
-
-
- /* Arrange for receipt of raw NET/ROM datagrams */
- struct raw_nr *
- raw_nr (protocol)
- char protocol;
- {
- register struct raw_nr *rp;
-
- rp = (struct raw_nr *) callocw (1, sizeof (struct raw_nr));
-
- rp->protocol = protocol;
- rp->next = Raw_nr;
- if (rp->next != NULLRNR)
- rp->next->prev = rp;
- Raw_nr = rp;
- return rp;
- }
-
-
- /* Free a raw NET/ROM descriptor */
- void
- del_rnr (rpp)
- struct raw_nr *rpp;
- {
- register struct raw_nr *rp;
-
- /* Do sanity check on arg */
- for (rp = Raw_nr; rp != NULLRNR; rp = rp->next)
- if (rp == rpp)
- break;
- if (rp == NULLRNR)
- return; /* Doesn't exist */
-
- /* Unlink */
- if (rp->prev != NULLRNR)
- rp->prev->next = rp->next;
- else
- Raw_nr = rp->next;
- if (rp->next != NULLRNR)
- rp->next->prev = rp->prev;
- /* Free resources */
- free_q (&rp->rcvq);
- free ((char *) rp);
- }
-
-
- /* Route net/rom network layer packets.
- */
- void
- nr_route (bp, iaxp)
- struct mbuf *bp; /* network packet */
- struct ax25_cb *iaxp; /* incoming ax25 control block */
- {
- struct nr3hdr n3hdr;
- struct nr4hdr n4hdr;
- struct ax25_cb *axp;
- struct mbuf *hbp, *pbp;
- struct raw_nr *rnr;
- register struct nrnbr_tab *np;
- register struct nrroute_tab *rp;
- register struct nr_bind *bindp;
- struct iface *iface;
-
- if (ntohnr3 (&n3hdr, &bp) == -1) {
- free_p (bp);
- return;
- }
- /* If this isn't an internally generated network packet,
- * give the router a chance to record a route back to the
- * sender, in case they aren't in the local node's routing
- * table yet.
- */
- if (iaxp != NULLAX25 /* && ax_lookup(iaxp->remote,iaxp->iface) != NULLAXR */ ) {
-
- /* find the interface number */
- if (!(iaxp->iface->flags & IS_NR_IFACE)) { /* Not a net/rom interface! */
- free_p (bp);
- return;
- }
- /* Add (possibly) a zero-quality recorded route via */
- /* the neighbor from which this packet was received */
- /* Note that this doesn't work with digipeated neighbors. */
-
- (void) nr_routeadd (temproute, n3hdr.source, iaxp->iface, 0, iaxp->remote, 0, 1);
- }
- /* Add some statictics gathering - WG7J */
- if (iaxp == NULLAX25) { /* a locally generated, ie outgoing, packet */
- Nr_iface->rawsndcnt++;
- Nr_iface->lastsent = secclock ();
- } else { /* incoming packet */
- Nr_iface->rawrecvcnt++;
- Nr_iface->lastrecv = secclock ();
- }
-
- /* A packet from me, to me, can only be one thing:
- * a horrible routing loop. This will probably result
- * from a bad manual ARP entry, but we should fix these
- * obscure errors as we find them.
- */
- if (addreq (Nr_iface->hwaddr, n3hdr.dest)) {
- /* Toss if from me, or if we can't read the header */
- if (iaxp == NULLAX25 || ntohnr4 (&n4hdr, &bp) == -1)
- free_p (bp);
- else if ((n4hdr.opcode & NR4OPCODE) == NR4OPPID) {
- for (rnr = Raw_nr; rnr != NULLRNR; rnr = rnr->next) {
- if ((unsigned char) rnr->protocol != n4hdr.u.pid.family ||
- (unsigned char) rnr->protocol != n4hdr.u.pid.proto)
- continue;
- /* Duplicate the data portion, and put the
- * level 3 header back on
- */
- (void) dup_p (&pbp, bp, 0, len_p (bp));
- if (pbp != NULLBUF &&
- (hbp = htonnr3 (&n3hdr)) != NULLBUF) {
- append (&hbp, pbp);
- enqueue (&rnr->rcvq, hbp);
- } else {
- free_p (pbp);
- free_p (hbp);
- }
- }
- /* IP does not use a NET/ROM level 3 socket */
- if (n4hdr.u.pid.family == NRPROTO_IP
- && n4hdr.u.pid.proto == NRPROTO_IP)
- (void) ip_route (iaxp->iface, bp, 0);
- else /* we don't do this proto */
- free_p (bp);
- } else {
- /* Must be net/rom transport: */
- nr4input (&n4hdr, bp);
- }
- return;
- }
- if ((rp = find_nrroute (n3hdr.dest)) == NULLNRRTAB) {
- /* no route, drop the packet */
- free_p (bp);
- return;
- }
- if ((bindp = find_best (rp->routes, 1)) == NULLNRBIND) {
- /* This shouldn't happen yet, but might if we add */
- /* dead route detection */
- free_p (bp);
- return;
- }
- np = bindp->via;
- iface = np->iface;
-
- /*Update the last-used timestamp - WG7J */
- np->lastsent = secclock ();
-
-
- /* Now check to see if iaxp is null. That is */
- /* a signal that the packet originates here, */
- /* so we need to insert the callsign of the appropriate */
- /* interface */
- if (iaxp == NULLAX25)
- memcpy (n3hdr.source, Nr_iface->hwaddr, AXALEN);
-
- /* Make sure there is a connection to the neighbor */
- /* Make sure we use the netrom-interface call for this connection!
- * 11/20/91 WG7J/PA3DIS
- */
- if ((axp = find_ax25 (Nr_iface->hwaddr, np->call, iface)) == NULLAX25 ||
- (axp->state != LAPB_CONNECTED && axp->state != LAPB_RECOVERY)) {
- /* Open a new connection or reinitialize old one */
- /* hwaddr has been advanced to point to neighbor + digis */
- axp = open_ax25 (iface, Nr_iface->hwaddr, np->call, AX_ACTIVE, Axwindow, s_arcall, s_atcall, s_ascall, -1);
- if (axp == NULLAX25) {
- free_p (bp);
- return;
- }
- }
- if (--n3hdr.ttl == 0) { /* the packet's time to live is over! */
- free_p (bp);
- return;
- }
- /* now format network header */
- if ((pbp = htonnr3 (&n3hdr)) == NULLBUF) {
- free_p (bp);
- return;
- }
- append (&pbp, bp); /* append data to header */
-
- /* put AX.25 PID on front */
- if ((bp = pushdown (pbp, 1)) == NULLBUF) {
- free_p (pbp);
- return;
- }
- bp->data[0] = PID_NETROM;
-
- if ((pbp = segmenter (bp, axp->paclen, axp)) == NULLBUF) {
- free_p (bp);
- return;
- }
- (void) send_ax25 (axp, pbp, -1); /* pass it off to ax25 code */
- }
-
-
- /* Perform a nodes broadcast on interface # ifno in the net/rom
- * interface table.
- */
- /* This uses Nralias as the alias instead of Nriface.alias as before - WG7J */
- void
- nr_bcnodes (ifp)
- struct iface *ifp;
- {
- struct mbuf *hbp, *dbp, *savehdr;
- struct nrroute_tab *rp;
- struct nrnbr_tab *np;
- struct nr_bind *bp;
- struct nr3dest nrdest;
- int i, didsend = 0, numdest = 0;
-
- /* prepare the header */
- if ((hbp = alloc_mbuf (NR3NODEHL)) == NULLBUF)
- return;
-
- hbp->cnt = NR3NODEHL;
-
- *hbp->data = NR3NODESIG;
-
- memcpy (hbp->data + 1, Nralias, ALEN);
-
- /* Some people don't want to advertise any routes; they
- * just want to be a terminal node. In that case we just
- * want to send our call and alias and be done with it.
- */
-
- if (!(ifp->flags & NR_VERBOSE)) {
- /*changed to use the Netrom interface call on all broadcasts,
- *INDEPENDENT from the actual interface call!
- *11/20/91 WG7J/PA3DIS
- */
- (void) (*ifp->output) (ifp, Ax25multi[NODESCALL], Nr_iface->hwaddr, PID_NETROM, hbp); /* send it */
- return;
- }
- /* make a copy of the header in case we need to send more than */
- /* one packet */
- savehdr = copy_p (hbp, NR3NODEHL);
-
- /* now scan through the routing table, finding the best routes */
- /* and their neighbors. create destination subpackets and append */
- /* them to the header */
- for (i = 0; i < NRNUMCHAINS; i++) {
- for (rp = Nrroute_tab[i]; rp != NULLNRRTAB; rp = rp->next) {
- /* look for best, non-obsolescent route */
- if ((bp = find_best (rp->routes, 0)) == NULLNRBIND)
- continue; /* no non-obsolescent routes found */
-
- if (bp->quality == 0) /* this is a loopback route */
- continue; /* we never broadcast these */
-
- if (bp->quality < Nr_autofloor) /* below threshhold route */
- continue; /* so don't broadcast it */
-
- if (nr_aliasck (rp->alias)) /* corrupted alias entry? */
- continue; /* don't rebroadcast it */
- /* safety measure! */
- np = bp->via;
- /* insert best neighbor */
- if (np && np->call)
- memcpy (nrdest.neighbor, np->call, AXALEN);
- else
- memcpy (nrdest.neighbor, rp->call, AXALEN);
- /* insert destination from route table */
- memcpy (nrdest.dest, rp->call, AXALEN);
- /* insert alias from route table */
- strcpy (nrdest.alias, rp->alias);
- /* insert quality from binding */
- nrdest.quality = bp->quality;
- /* create a network format destination subpacket */
- if ((dbp = htonnrdest (&nrdest)) == NULLBUF) {
- free_p (hbp); /* drop the whole idea ... */
- free_p (savehdr);
- return;
- }
- /* we now have a partially filled packet */
- didsend = 0;
- append (&hbp, dbp); /* append to header and others */
- /* see if we have appended as many destinations
- * as we can fit into a single broadcast. If we
- * have, go ahead and send them out.
- */
- if (++numdest == NRDESTPERPACK) { /* filled it up */
- /* indicate that we did broadcast */
- didsend = 1;
- /* reset the destination counter */
- numdest = 0;
- (void) (*ifp->output) (ifp, Ax25multi[NODESCALL], Nr_iface->hwaddr, PID_NETROM, hbp); /* send it */
- /* new header */
- hbp = copy_p (savehdr, NR3NODEHL);
- }
- }
- }
-
- /* If we have a partly filled packet left over, or we never */
- /* sent one at all, we broadcast: */
-
- if (!didsend || numdest > 0)
- (void) (*ifp->output) (ifp, Ax25multi[NODESCALL], Nr_iface->hwaddr, PID_NETROM, hbp);
- else {
- if (numdest == 0) /* free the header copies */
- free_p (hbp);
- }
-
- free_p (savehdr);
- }
-
-
- /* Perform a nodes broadcast poll on interface ifp
- * in the net/rom interface table. - WG7J
- */
- void
- nr_bcpoll (ifp)
- struct iface *ifp;
- {
- struct mbuf *hbp;
-
- /* prepare the header */
- if ((hbp = alloc_mbuf (NR3NODEHL)) == NULLBUF)
- return;
- hbp->cnt = NR3NODEHL;
- *hbp->data = NR3POLLSIG;
- memcpy (hbp->data + 1, Nralias, ALEN);
-
- /* send it out */
- (void) (*ifp->output) (ifp, Ax25multi[1], Nr_iface->hwaddr, PID_NETROM, hbp);
- return;
- }
-
-
- extern struct timer Nodetimer, Obsotimer;
-
- /* attach the net/rom interface. no parms for now. */
- int
- nr_attach (argc, argv, p)
- int argc OPTIONAL;
- char *argv[] OPTIONAL;
- void *p OPTIONAL;
- {
- if (Nr_iface != (struct iface *) 0) {
- tputs ("netrom interface already attached\n");
- return -1;
- }
- Nr_iface = (struct iface *) callocw (1, sizeof (struct iface));
-
- Nr_iface->addr = Ip_addr;
- Nr_iface->iface_metric = 1;
-
- /* The strdup is needed to keep the detach routine happy (it'll
- * free the allocated memory)
- */
- Nr_iface->name = strdup ("netrom");
- if (Nr_iface->hwaddr == NULLCHAR) {
- Nr_iface->hwaddr = mallocw (AXALEN);
- memcpy (Nr_iface->hwaddr, Mycall, AXALEN);
- }
- Nr_iface->mtu = NR4MAXINFO;
- (void) setencap (Nr_iface, "NETROM");
- Nr_iface->next = Ifaces;
- Ifaces = Nr_iface;
- memcpy (Nr4user, Mycall, AXALEN);
-
- /* Added some default settings for node-broadcast interval and
- * obsolescence timers. 11/21/91 WG7J/PA3DIS
- */
- stop_timer (&Nodetimer);
- Nodetimer.func = (void (*)(void *)) donodetick; /* what to call on timeout */
- Nodetimer.arg = NULLCHAR; /* dummy value */
- set_timer (&Nodetimer, 1800000L); /* 'standard netrom' 30 minutes*/
- start_detached_timer (&Nodetimer); /* and fire it up */
-
- stop_timer (&Obsotimer);
- Obsotimer.func = (void (*)(void *)) doobsotick; /* what to call on timeout */
- Obsotimer.arg = NULLCHAR; /* dummy value */
- set_timer (&Obsotimer, 2100000L); /* 35 minutes */
- start_detached_timer (&Obsotimer); /* and fire it up */
-
- return 0;
- }
-
-
- /* This function checks an ax.25 address and interface number against
- * the filter table and mode, and returns -1 if the address is to be accepted
- * verbatim, the quality if filtered in or 0 if it is to be filtered out.
- */
- static int
- accept_bc (addr, ifp)
- char *addr;
- struct iface *ifp;
- {
- struct nrnf_tab *fp;
-
- if (Nr_nfmode == NRNF_NOFILTER) /* no filtering in effect */
- return -1;
-
- fp = find_nrnf (addr, ifp); /* look it up */
-
- if (fp != NULLNRNFTAB && Nr_nfmode == NRNF_ACCEPT)
- return ((int)fp->quality);
-
- if (fp == NULLNRNFTAB && Nr_nfmode == NRNF_REJECT)
- return -1;
-
- if (Nr_promisc)
- return -1; /* Come up and see me sometime..... */
- else
- return 0; /* My mummy said not to listen to strangers! */
- }
-
-
- /* receive and process node broadcasts. */
- void
- nr_nodercv (iface, source, bp)
- struct iface *iface;
- char *source;
- struct mbuf *bp;
- {
- char bcalias[AXALEN];
- struct nr3dest ds;
- int qual, poll;
- unsigned char c;
- struct mbuf **bpp = &bp;
-
- /* First, see if this is even a net/rom interface: */
- if (!(iface->flags & IS_NR_IFACE)) {
- free_p (bp);
- return;
- }
- if ((qual = accept_bc (source, iface)) == 0) { /* check against filter */
- free_p (bp); /* and get quality */
- return;
- }
- c = uchar(PULLCHAR (bpp));
- /* is this a route update poll from a neigbour ? - WG7J */
- poll = 0;
- if (c == NR3POLLSIG) {
- poll = 1;
- nr_bcnodes (iface); /* broadcast our routes */
- } else /* See if it has a routing broadcast signature: */
- if (c != NR3NODESIG) {
- free_p (bp);
- return;
- }
- /* now try to get the alias */
- if (pullup (&bp, (unsigned char *) bcalias, ALEN) < ALEN) {
- free_p (bp);
- return;
- }
- /* now check that the alias field is not corrupted - saftey measure! */
- if (nr_aliasck (bcalias)) {
- free_p (bp);
- return;
- }
- bcalias[ALEN] = '\0'; /* null terminate */
-
- #ifdef NR_BC_RESPOND
- /* If we were polled, we've already sent the routes list - WG7J */
- if (!poll && (find_nrnbr (source, iface) == NULLNTAB)) /* a new node ! */
- nr_bcnodes (iface);
- #endif
-
- /* enter the neighbor into our routing table */
- if (qual == -1)
- qual = iface->quality; /* use default quality */
-
- if (nr_routeadd (bcalias, source, iface, (unsigned) qual, source, 0, 0) == -1) {
- free_p (bp);
- return;
- }
- /* we've digested the header; now digest the actual */
- /* routing information */
- while (ntohnrdest (&ds, &bp) != -1) {
-
- /* ignore routes to me! */
- if (addreq (Nr_iface->hwaddr, ds.dest))
- continue;
-
- /* ignore routes with corrupted aliases - safety measure */
- if (nr_aliasck (ds.alias))
- continue;
-
- /* ignore loopback paths to ourselves */
- if (addreq (Nr_iface->hwaddr, ds.neighbor))
- continue;
- else
- ds.quality = ((ds.quality * (int16) qual + 128) / 256) & 0xff;
-
- /* ignore routes below the minimum quality threshhold */
- if (ds.quality < Nr_autofloor)
- continue;
-
- if (nr_routeadd (ds.alias, ds.dest, iface, ds.quality, source, 0, 0)
- == -1)
- break;
- }
- free_p (bp); /* This will free the mbuf if anything fails above */
- }
-
-
- /* The following are utilities for manipulating the routing table */
-
- /* hash function for callsigns. Look familiar? */
- int16
- nrhash (s)
- char *s;
- {
- register char x;
- register int i;
-
- x = 0;
- for (i = ALEN; i != 0; i--)
- x ^= (char)(*s++ & 0xfe);
- x ^= *s & SSID;
- return (int16) (uchar (x) % NRNUMCHAINS);
- }
-
-
- /* Find a neighbor table entry. Neighbors are determined by
- * their callsign and the interface number. This takes care
- * of the case where the same switch or hosts uses the same
- * callsign on two different channels. This isn't done by
- * net/rom, but it might be done by stations running *our*
- * software.
- */
- struct nrnbr_tab *
- find_nrnbr (addr, ifp)
- register char *addr;
- struct iface *ifp;
- {
- int16 hashval;
- register struct nrnbr_tab *np;
-
- /* Find appropriate hash chain */
- hashval = nrhash (addr);
-
- /* search hash chain */
- for (np = Nrnbr_tab[hashval]; np != NULLNTAB; np = np->next) {
- /* convert first in list to ax25 address format */
- if (addreq (np->call, addr) && np->iface == ifp) {
- return np;
- }
- }
- return NULLNTAB;
- }
-
-
- /* Try to find the AX.25 address of a node with the given call or alias.
- * Return a pointer to the route if found, otherwize NULLNRRTAB.
- * alias should be a six character, blank-padded, upper-case string.
- * call should be a upper-case string.
- * 12-21-91, WG7J
- */
-
- struct nrroute_tab *
- find_nrboth (alias, call)
- char *alias;
- char *call;
- {
- int i;
- register struct nrroute_tab *rp;
- char tmp[AXBUF];
-
- /* Since the route entries are hashed by ax.25 address, we'll */
- /* have to search all the chains */
-
- for (i = 0; i < NRNUMCHAINS; i++)
- for (rp = Nrroute_tab[i]; rp != NULLNRRTAB; rp = rp->next)
- if ((strncmp (alias, rp->alias, 6) == 0) ||
- (strcmp (call, pax25 (tmp, rp->call)) == 0))
- return rp;
-
- /* If we get to here, we're out of luck */
- return NULLNRRTAB;
- }
-
-
- /* Find a route table entry */
- struct nrroute_tab *
- find_nrroute (addr)
- register char *addr;
- {
- int16 hashval;
- register struct nrroute_tab *rp;
-
- /* Find appropriate hash chain */
- hashval = nrhash (addr);
-
- if (hashval >= NRNUMCHAINS) /* should NEVER happen */
- return NULLNRRTAB;
-
- /* search hash chain */
- for (rp = Nrroute_tab[hashval]; rp != NULLNRRTAB; rp = rp->next) {
- if (addreq (rp->call, addr)) {
- return rp;
- }
- }
- return NULLNRRTAB;
- }
-
-
- #if 0
- /* Try to find the AX.25 address of a node with the given alias. Return */
- /* a pointer to the AX.25 address if found, otherwise NULLCHAR. The alias */
- /* should be a six character, blank-padded, upper-case string. */
-
- static char *
- find_nralias (alias)
- char *alias;
- {
- int i;
- register struct nrroute_tab *rp;
-
- /* Since the route entries are hashed by ax.25 address, we'll */
- /* have to search all the chains */
-
- for (i = 0; i < NRNUMCHAINS; i++)
- for (rp = Nrroute_tab[i]; rp != NULLNRRTAB; rp = rp->next)
- if (strncmp (alias, rp->alias, 6) == 0)
- return rp->call;
-
- /* If we get to here, we're out of luck */
-
- return NULLCHAR;
- }
- #endif
-
-
- /* Find a binding in a list by its neighbor structure's address */
- static struct nr_bind *
- find_binding (list, neighbor)
- struct nr_bind *list;
- register struct nrnbr_tab *neighbor;
- {
- register struct nr_bind *bp;
-
- for (bp = list; bp != NULLNRBIND; bp = bp->next)
- if (bp->via == neighbor)
- return bp;
-
- return NULLNRBIND;
- }
-
-
- /* Find the worst quality non-permanent binding in a list */
- static
- struct nr_bind *
- find_worst (list)
- struct nr_bind *list;
- {
- register struct nr_bind *bp;
- struct nr_bind *worst = NULLNRBIND;
- unsigned minqual = 1000;/* infinity */
-
- for (bp = list; bp != NULLNRBIND; bp = bp->next)
- if (!(bp->flags & NRB_PERMANENT) && bp->quality < minqual) {
- worst = bp;
- minqual = bp->quality;
- }
- return worst;
- }
-
-
- /* Find the best binding of any sort in a list. If obso is 1,
- * include entries below the obsolescence threshhold in the
- * search (used when this is called for routing broadcasts).
- * If it is 0, routes below the threshhold are treated as
- * though they don't exist.
- */
- struct nr_bind *
- find_best (list, obso)
- struct nr_bind *list;
- unsigned obso;
- {
- register struct nr_bind *bp;
- struct nr_bind *best = NULLNRBIND;
- int maxqual = -1; /* negative infinity */
-
- for (bp = list; bp != NULLNRBIND; bp = bp->next)
- if ((int) bp->quality > maxqual)
- if (obso || bp->obsocnt >= Obso_minbc) {
- best = bp;
- maxqual = (int) bp->quality;
- }
- return best;
- }
-
-
- /* Add a route to the net/rom routing table */
- int
- nr_routeadd (alias, dest, ifp, quality, neighbor, permanent, record)
- const char *alias; /* net/rom node alias, blank-padded and null-terminated */
- char *dest; /* destination node callsign */
- struct iface *ifp;
- unsigned quality; /* route quality */
- char *neighbor; /* neighbor node + 2 digis (max) in arp format */
- unsigned permanent; /* 1 if route is permanent (hand-entered) */
- unsigned record; /* 1 if route is a "record route" */
- {
- struct nrroute_tab *rp;
- struct nr_bind *bp;
- struct nrnbr_tab *np;
- int16 rhash, nhash;
-
- /* See if a routing table entry exists for this destination */
- if ((rp = find_nrroute (dest)) == NULLNRRTAB) {
- rp = (struct nrroute_tab *) callocw (1, sizeof (struct nrroute_tab));
-
- /* create a new route table entry */
- strncpy (rp->alias, alias, 6);
- memcpy (rp->call, dest, AXALEN);
- rhash = nrhash (dest);
- rp->next = Nrroute_tab[rhash];
- if (rp->next != NULLNRRTAB)
- rp->next->prev = rp;
- Nrroute_tab[rhash] = rp; /* link at head of hash chain */
- } else if (permanent || !strncmp (rp->alias, temproute, 6))
- strncpy (rp->alias, alias, 6); /* update the alias */
-
- /* See if an entry exists for this neighbor */
- if ((np = find_nrnbr (neighbor, ifp)) == NULLNTAB) {
- np = (struct nrnbr_tab *) callocw (1, sizeof (struct nrnbr_tab));
-
- /* create a new neighbor entry */
- memcpy (np->call, neighbor, AXALEN);
- np->iface = ifp;
- nhash = nrhash (neighbor);
- np->next = Nrnbr_tab[nhash];
- if (np->next != NULLNTAB)
- np->next->prev = np;
- Nrnbr_tab[nhash] = np;
- } else if (permanent) /* force this path to the neighbor */
- memcpy (np->call, neighbor, AXALEN);
-
- /* See if there is a binding between the dest and neighbor */
- if ((bp = find_binding (rp->routes, np)) == NULLNRBIND) {
- bp = (struct nr_bind *) callocw (1, sizeof (struct nr_bind));
-
- /* create a new binding and link it in */
- bp->via = np; /* goes via this neighbor */
- bp->next = rp->routes; /* link into binding chain */
- if (bp->next != NULLNRBIND)
- bp->next->prev = bp;
- rp->routes = bp;
- rp->num_routes++; /* bump route count */
- np->refcnt++; /* bump neighbor ref count */
- bp->quality = quality;
- bp->obsocnt = Obso_init; /* use initial value */
- if (permanent)
- bp->flags |= NRB_PERMANENT;
- else if (record)/* notice permanent overrides record! */
- bp->flags |= NRB_RECORDED;
- } else {
- if (permanent) {/* permanent request trumps all */
- bp->quality = quality;
- bp->obsocnt = Obso_init;
- bp->flags |= NRB_PERMANENT;
- bp->flags &= ~NRB_RECORDED; /* perm is not recorded */
- } else if (!(bp->flags & NRB_PERMANENT)) { /* not permanent */
- if (record) { /* came from nr_route */
- if (bp->flags & NRB_RECORDED) { /* no mod non-rec bindings */
- bp->quality = quality;
- bp->obsocnt = Obso_init; /* freshen recorded routes */
- }
- } else {/* came from a routing broadcast */
- bp->quality = quality;
- bp->obsocnt = Obso_init;
- bp->flags &= ~NRB_RECORDED; /* no longer a recorded route */
- }
- }
- }
-
- /* Now, check to see if we have too many bindings, and drop */
- /* the worst if we do */
- if (rp->num_routes > Nr_maxroutes) {
- /* since find_worst never returns permanent entries, the */
- /* limitation on number of routes is circumvented for */
- /* permanent routes */
- if ((bp = find_worst (rp->routes)) != NULLNRBIND) {
- (void) nr_routedrop (dest, bp->via->call, bp->via->iface);
- }
- }
- return 0;
- }
-
-
- /* Reset the netrom links to this neighbour, since the
- * route to it just expired - WG7J
- */
- void
- nrresetlinks (struct nrroute_tab *rp)
- {
- int i;
- struct nr4cb *cb;
-
- for (i = 0; i < NR4MAXCIRC; i++)
- if ((cb = Nr4circuits[i].ccb) != NULLNR4CB)
- if (!memcmp (cb->remote.node, rp->call, AXALEN))
- reset_nr4 (cb);
- }
-
-
- /* Drop a route to dest via neighbor */
- int
- nr_routedrop (dest, neighbor, ifp)
- char *dest, *neighbor;
- struct iface *ifp;
- {
- register struct nrroute_tab *rp;
- register struct nrnbr_tab *np;
- register struct nr_bind *bp;
-
- if ((rp = find_nrroute (dest)) == NULLNRRTAB)
- return -1;
-
- if ((np = find_nrnbr (neighbor, ifp)) == NULLNTAB)
- return -1;
-
- if ((bp = find_binding (rp->routes, np)) == NULLNRBIND)
- return -1;
-
- /* drop the binding first */
- if (bp->next != NULLNRBIND)
- bp->next->prev = bp->prev;
- if (bp->prev != NULLNRBIND)
- bp->prev->next = bp->next;
- else
- rp->routes = bp->next;
-
- free ((char *) bp);
- rp->num_routes--; /* decrement the number of bindings */
- np->refcnt--; /* and the number of neighbor references */
-
- /* now see if we should drop the route table entry */
- if (rp->num_routes == 0) {
- if (rp->next != NULLNRRTAB)
- rp->next->prev = rp->prev;
- if (rp->prev != NULLNRRTAB)
- rp->prev->next = rp->next;
- else
- Nrroute_tab[nrhash (dest)] = rp->next;
- /* No more routes left !
- * We should close/reset any netrom connections
- * still idling for this route ! - WG7J
- */
- nrresetlinks (rp);
-
- free ((char *) rp);
- }
- /* and check to see if this neighbor can be dropped */
- if (np->refcnt == 0) {
- if (np->next != NULLNTAB)
- np->next->prev = np->prev;
- if (np->prev != NULLNTAB)
- np->prev->next = np->next;
- else
- Nrnbr_tab[nrhash (neighbor)] = np->next;
-
- free ((char *) np);
- }
- return 0;
- }
-
-
- /* Find an entry in the filter table */
- static struct nrnf_tab *
- find_nrnf (addr, ifp)
- register char *addr;
- struct iface *ifp;
- {
- int16 hashval;
- register struct nrnf_tab *fp;
-
- /* Find appropriate hash chain */
- hashval = nrhash (addr);
-
- /* search hash chain */
- for (fp = Nrnf_tab[hashval]; fp != NULLNRNFTAB; fp = fp->next) {
- if (addreq (fp->neighbor, addr) && (fp->iface == ifp)) {
- return fp;
- }
- }
-
- return NULLNRNFTAB;
- }
-
-
- /* Add an entry to the filter table. Return 0 on success,
- * -1 on failure
- */
- int
- nr_nfadd (addr, ifp, qual)
- char *addr;
- struct iface *ifp;
- unsigned qual;
- {
- struct nrnf_tab *fp;
- int16 hashval;
-
- if (find_nrnf (addr, ifp) != NULLNRNFTAB)
- return 0; /* already there; it's a no-op */
-
- fp = (struct nrnf_tab *) callocw (1, sizeof (struct nrnf_tab));
-
- hashval = nrhash (addr);
- memcpy (fp->neighbor, addr, AXALEN);
- fp->iface = ifp;
- fp->next = Nrnf_tab[hashval];
- fp->quality = qual;
- if (fp->next != NULLNRNFTAB)
- fp->next->prev = fp;
- Nrnf_tab[hashval] = fp;
-
- return 0;
- }
-
-
- /* Drop a neighbor from the filter table. Returns 0 on success, -1
- * on failure.
- */
- int
- nr_nfdrop (addr, ifp)
- char *addr;
- struct iface *ifp;
- {
- struct nrnf_tab *fp;
-
- if ((fp = find_nrnf (addr, ifp)) == NULLNRNFTAB)
- return -1; /* not in the table */
-
- if (fp->next != NULLNRNFTAB)
- fp->next->prev = fp->prev;
- if (fp->prev != NULLNRNFTAB)
- fp->prev->next = fp->next;
- else
- Nrnf_tab[nrhash (addr)] = fp->next;
-
- free ((char *) fp);
-
- return 0;
- }
-
-
- /*
- * Validate the alias field is good quality ascii to prevent network corruption
- */
-
- static int
- nr_aliasck (alias)
- char *alias;
- {
- int x = ALEN;
- int c;
-
- while (x--) {
- c = *alias++;
- if (!isprint ((int) c))
- return 1;
- }
- return 0;
- }
-
-
- /* called from lapb whenever a link failure implies that a particular ax25
- * path may not be able to carry netrom traffic too well. Experimental!!!!
- */
- void
- nr_derate (axp)
- struct ax25_cb *axp;
- {
- register struct nrnbr_tab *np;
- register struct nrroute_tab *rp;
- register struct nr_bind *bp;
- struct mbuf *buf;
- int i;
- int nr_traffic = 0; /* assume no netrom traffic on connection */
-
- if (!Nr_derate)
- return; /* derating function is disabled */
-
- /* is this an active netrom interface ? */
- if (!(axp->iface->flags & IS_NR_IFACE))
- return;
-
- if (axp == NULLAX25)
- return; /* abandon ship! */
-
- /* If it is valid for netrom traffic, lets see if there is */
- /* really netrom traffic on the connection to be derated. */
- for (buf = axp->txq; buf != NULLBUF; buf = buf->anext)
- if ((buf->data[0] & 0xff) == PID_NETROM)
- nr_traffic = 1; /* aha - netrom traffic! */
-
- if (!nr_traffic)
- return; /* no sign of being used by netrom just now */
-
- /* we now have the appropriate interface entry */
- for (i = 0; i < NRNUMCHAINS; i++) {
- for (rp = Nrroute_tab[i]; rp != NULLNRRTAB; rp = rp->next) {
- for (bp = rp->routes; bp != NULLNRBIND; bp = bp->next) {
- np = bp->via;
- if (bp->quality >= 1 && np->iface == axp->iface &&
- !(bp->flags & NRB_PERMANENT) &&
- !memcmp (np->call, axp->remote, ALEN) &&
- (np->call[6] & SSID) == (axp->remote[6] & SSID)) {
- bp->quality = ((bp->quality * 2) / 3);
- }
- }
- }
- }
- }
-
- #endif /* NETROM */
-